package delta;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class Main {

	private static String outputFile = null;
	private static Mordor mordor;
	private static String generateEnemyMode = "AUTO";
	private static String fogControlMode = "AUTO";
	private static Map<Integer, Fog> fogMap = new HashMap<Integer, Fog>();
	private static List<Obstacle> obstacles = new ArrayList<Obstacle>();
	private static List<Tower> towers = new ArrayList<Tower>();

	public static List<BufferedWriter> bw = new ArrayList<BufferedWriter>();

	public static void main(String[] args) {

		try {
			bw.add(new BufferedWriter(new OutputStreamWriter(System.out)));
			saveToFile("output.txt");
			BufferedReader br;
			if (args.length > 0) {
				for (String filename : args) {
					loadFromFile(filename);
				}
			}
			br = new BufferedReader(new InputStreamReader(System.in));
			execute(br);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void execute(BufferedReader br) {
		String line;
		try {

			line = br.readLine();
			while (line != null) {

				line.trim();
				String[] command = line.split("\\(");
				if (command[0].equals("saveToFile")) {
					saveToFile(command[1].replace(")", "").replace("\"", "").trim());
				} else if (command[0].trim().equals("loadFromFile")) {
					loadFromFile(command[1].replace(")", "").replace("\"", "").trim());
				} else if (command[0].trim().equals("commandsBegin")) {
					line = br.readLine();
					if (line != null) {
						while (!command[0].trim().equals("commandsEnd")) {
							command = line.split("\\(");
							if (command[0].trim().equals("initPlayer")) {
								if (command[1].replace(")", "").replace("\"", "").trim().equals("")) {
									initPlayer();
								} else {
									try {
										initPlayer(Integer.parseInt(command[1].replace(")", "").replace("\"", "").trim()));
									} catch (NumberFormatException e) {
										writeOut("A varazseronek szamnak kell lennie!");
									}
								}
							} else if (command[0].trim().equals("createMapBegin")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								createMapBegin(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()), br);
							} else if (command[0].trim().equals("autoCreateMap")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								autoGenerateMap(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
							} else if (command[0].trim().equals("fogControl")) {
								if (command[1].replace(")", "").trim().equals("AUTO")) {
									fogControlMode = "AUTO";
								} else if (command[1].replace(")", "").trim().equals("MANUAL")) {
									fogControlMode = "MANUAL";
								} else {
									writeOut("Syntax error: AUTO vagy MANUAL");
								}

							} else if (command[0].trim().equals("generateEnemy")) {
								if (command[1].replace(")", "").trim().equals("AUTO")) {
									generateEnemyMode = "AUTO";
								} else if (command[1].replace(")", "").trim().equals("MANUAL")) {
									generateEnemyMode = "MANUAL";
								} else {
									writeOut("Syntax error: AUTO vagy MANUAL");
								}
							} else if (command[0].trim().equals("placeEnemy")) {
								if (generateEnemyMode.equals("MANUAL")) {
									String[] commandParams = command[1].replace(")", "").split(",");
									switch (commandParams.length) {
									case 0:
										placeEnemy();
										break;
									case 1:
										placeEnemy(commandParams[0]);
										break;
									case 2:
										placeEnemy(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
										break;
									case 3:
										placeEnemy(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()),
												commandParams[2].trim());
										break;
									}
								} else {
									writeOut("generateEnemy(MANUAL) utan adhatsz ki placeEnemy parancsot.");
								}
							} else if (command[0].trim().equals("placeObstacle")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length > 0) {
									placeObstacle(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
								} else {
									placeObstacle();
								}
							} else if (command[0].trim().equals("placeTower")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length > 0) {
									placeTower(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
								} else {
									placeTower();
								}
							} else if (command[0].trim().equals("placeMagicStoneToTower1")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length > 0) {
									placeMagicStoneToTower1(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
								} else {
									placeMagicStoneToTower1();
								}
							} else if (command[0].trim().equals("placeMagicStoneToTower2")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length > 0) {
									placeMagicStoneToTower2(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
								} else {
									placeMagicStoneToTower2();
								}
							} else if (command[0].trim().equals("placeMagicStoneToTower3")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length > 0) {
									placeMagicStoneToTower1(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
								} else {
									placeMagicStoneToTower1();
								}
							} else if (command[0].trim().equals("placeMagicStoneToTower4")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length > 0) {
									placeMagicStoneToTower2(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
								} else {
									placeMagicStoneToTower2();
								}

							} else if (command[0].trim().equals("placeMagicStoneToObstacle")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length > 0) {
									placeMagicStoneToObstacle(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()));
								} else {
									placeMagicStoneToObstacle();
								}

							} else if (command[0].trim().equals("addFogToField")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length == 4) {
									addFogToField(Integer.parseInt(commandParams[0].trim()), Integer.parseInt(commandParams[1].trim()),
											Integer.parseInt(commandParams[2].trim()), commandParams[3].trim().equals("true"));
								} else {
									writeOut("Syntax error!");
								}

							} else if (command[0].trim().equals("removeFog")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length == 1) {
									removeFog(Integer.parseInt(commandParams[0].trim()));
								} else {
									writeOut("Syntax error!");
								}

							} else if (command[0].trim().equals("moveFog")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length == 1) {
									moveFog(Integer.parseInt(commandParams[0].trim()));
								} else {
									writeOut("Syntax error!");
								}

							} else if (command[0].trim().equals("simulateWorld")) {
								String[] commandParams = command[1].replace(")", "").split(",");
								if (commandParams.length == 1) {
									simulateWorld(Integer.parseInt(commandParams[0].trim()));
								} else {
									writeOut("Syntax error!");
								}

							} else if (command[0].trim().equals("print")) {
								print();

							} else {

								writeOut("Syntax error!");

							}
							line = br.readLine();
							if (line == null) {
								writeOut("Fatal error!");
								exit();
							}
							command = line.split("\\(");
						}

					} else {
						writeOut("Fatal error");
						exit();

					}

				} else if (command[0].trim().equals("exit")) {
					exit();
				} else if (command[0].trim().equals("compareTo")) {
						OutputComparer.compareOutPut(outputFile, command[1].replace(")", "").replace("\"", "").trim());
				} else if (command[0].equals("")) {

				} else {
					writeOut("Syntax error!");

				}
				line = br.readLine();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void placeEnemy() throws IOException {
		Random rand = new Random();
		switch (rand.nextInt(4)) {
		case 0:
			new Dwarf(mordor.getRandomStartRoad());
			writeOut("Dwarf hozzaadva");
			break;
		case 1:
			new Elf(mordor.getRandomStartRoad());
			writeOut("Elf hozzaadva");
			break;
		case 2:
			new Hobbit(mordor.getRandomStartRoad());
			writeOut("Hobbit hozzaadva");
			break;
		case 3:
			new Human(mordor.getRandomStartRoad());
			break;
		}
	}

	public static void placeEnemy(String type) throws IOException {
		if (type.equalsIgnoreCase("DWARF")) {
			new Dwarf(mordor.getRandomStartRoad());
			writeOut("Dwarf hozzaadva");
		} else if (type.equalsIgnoreCase("ELF")) {
			new Elf(mordor.getRandomStartRoad());
			writeOut("Elf hozzaadva");
		} else if (type.equalsIgnoreCase("HOBBIT")) {
			new Hobbit(mordor.getRandomStartRoad());
			writeOut("Hobbit hozzaadva");
		} else if (type.equalsIgnoreCase("HUMAN")) {
			new Human(mordor.getRandomStartRoad());
			writeOut("Human hozzaadva");
		} else
			writeOut("Nincs ilyen tipusu ellenfel");
	}

	public static void placeEnemy(int x, int y) throws IOException {
		Random rand = new Random();
		switch (rand.nextInt(4)) {
		case 0:
			new Dwarf((Road) mordor.getField(x, y));
			writeOut("Dwarf hozzaadva");
			break;
		case 1:
			new Elf((Road) mordor.getField(x, y));
			writeOut("Elf hozzaadva");
			break;
		case 2:
			new Hobbit((Road) mordor.getField(x, y));
			writeOut("Hobbit hozzaadva");
			break;
		case 3:
			new Human((Road) mordor.getField(x, y));
			writeOut("Human hozzaadva");
			break;
		}
	}

	public static void placeEnemy(int x, int y, String type) throws IOException {
		if (type.equalsIgnoreCase("DWARF")) {
			new Dwarf((Road) mordor.getField(x - 1, y - 1));
			writeOut("Dwarf hozzaadva");
		} else if (type.equalsIgnoreCase("ELF")) {
			new Elf((Road) mordor.getField(x, y));
			writeOut("Elf hozzaadva");
		} else if (type.equalsIgnoreCase("HOBBIT")) {
			new Hobbit((Road) mordor.getField(x, y));
			writeOut("Hobbit hozzaadva");
		} else if (type.equalsIgnoreCase("HUMAN")) {
			new Human((Road) mordor.getField(x, y));
			writeOut("Human hozzaadva");
		} else
			writeOut("Nincs ilyen tipusu ellenfel");
	}

	public static void placeObstacle(int x, int y) throws IOException {
		new Obstacle((Road) mordor.getField(x, y));
		writeOut("akadaly hozzaadva");
	}

	public static void placeObstacle() {
		// obstacles.add(obstacle);

	}

	public static void placeTower(int x, int y) throws IOException {
		new Tower(mordor.getField(x, y));
		writeOut("torony hozzaadva");
	}

	public static void placeTower() {
		// towers.add(tower);

	}

	public static void placeMagicStoneToTower1(int x, int y) throws IOException {
		boolean hasTower = false;
		List<IFieldable> objects = mordor.getField(x, y).getObjects();
		for (IFieldable iFieldable : objects) {
			if (iFieldable instanceof Tower) {
				hasTower = true;
				if (((Tower) iFieldable).AddMagicStone(new MagicStoneToTower1())) {
					writeOut("Varazsko1 hozzaadva");
				} else {
					writeOut("Nem lehet varazskovet elhelyezni");
				}
			}
		}
		if (!hasTower) {
			writeOut("Nem lehet varazskovet elhelyezni");
		}
	}

	public static void placeMagicStoneToTower1() throws IOException {
		if (towers.size() < 1) {
			writeOut("Nem lehet varazskovet elhelyezni");
		} else {
			Random rand = new Random();
			if (towers.get(rand.nextInt(towers.size())).AddMagicStone(new MagicStoneToTower1())) {
				writeOut("Varazsko1 hozzaadva");
			} else {
				writeOut("Nem lehet varazskovet elhelyezni");
			}
		}

	}

	public static void placeMagicStoneToTower2(int x, int y) throws IOException {
		boolean hasTower = false;
		List<IFieldable> objects = mordor.getField(x, y).getObjects();
		for (IFieldable iFieldable : objects) {
			if (iFieldable instanceof Tower) {
				hasTower = true;
				if (((Tower) iFieldable).AddMagicStone(new MagicStoneToTower2())) {
					writeOut("Varazsko2 hozzaadva");
				} else {
					writeOut("Nem lehet varazskovet elhelyezni");
				}
			}
		}
		if (!hasTower) {
			writeOut("Nem lehet varazskovet elhelyezni");
		}

	}

	public static void placeMagicStoneToTower2() throws IOException {
		if (towers.size() < 1) {
			writeOut("Nem lehet varazskovet elhelyezni");
		} else {
			Random rand = new Random();
			if (towers.get(rand.nextInt(towers.size())).AddMagicStone(new MagicStoneToTower2())) {
				writeOut("Varazsko2 hozzaadva");
			} else {
				writeOut("Nem lehet varazskovet elhelyezni");
			}
		}
	}

	public static void placeMagicStoneToTower3(int x, int y) throws IOException {
		boolean hasTower = false;
		List<IFieldable> objects = mordor.getField(x, y).getObjects();
		for (IFieldable iFieldable : objects) {
			if (iFieldable instanceof Tower) {
				hasTower = true;
				if (((Tower) iFieldable).AddMagicStone(new MagicStoneToTower3())) {
					writeOut("Varazsko3 hozzaadva");
				} else {
					writeOut("Nem lehet varazskovet elhelyezni");
				}
			}
		}
		if (!hasTower) {
			writeOut("Nem lehet varazskovet elhelyezni");
		}

	}

	public static void placeMagicStoneToTower3() throws IOException {
		if (towers.size() < 1) {
			writeOut("Nem lehet varazskovet elhelyezni");
		} else {
			Random rand = new Random();
			if (towers.get(rand.nextInt(towers.size())).AddMagicStone(new MagicStoneToTower3())) {
				writeOut("Varazsko3 hozzaadva");
			} else {
				writeOut("Nem lehet varazskovet elhelyezni");
			}
		}
	}

	public static void placeMagicStoneToTower4(int x, int y) throws IOException {
		boolean hasTower = false;
		List<IFieldable> objects = mordor.getField(x, y).getObjects();
		for (IFieldable iFieldable : objects) {
			if (iFieldable instanceof Tower) {
				hasTower = true;
				if (((Tower) iFieldable).AddMagicStone(new MagicStoneToTower4())) {
					writeOut("Varazsko4 hozzaadva");
				} else {
					writeOut("Nem lehet varazskovet elhelyezni");
				}
			}
		}
		if (!hasTower) {
			writeOut("Nem lehet varazskovet elhelyezni");
		}

	}

	public static void placeMagicStoneToTower4() throws IOException {
		if (towers.size() < 1) {
			writeOut("Nem lehet varazskovet elhelyezni");
		} else {
			Random rand = new Random();
			if (towers.get(rand.nextInt(towers.size())).AddMagicStone(new MagicStoneToTower4())) {
				writeOut("Varazsko4 hozzaadva");
			} else {
				writeOut("Nem lehet varazskovet elhelyezni");
			}
		}
	}

	public static void placeMagicStoneToObstacle(int x, int y) throws IOException {
		boolean hasObstacle = false;
		List<IFieldable> objects = mordor.getField(x, y).getObjects();
		for (IFieldable iFieldable : objects) {
			if (iFieldable instanceof Obstacle) {
				hasObstacle = true;
				if (((Tower) iFieldable).AddMagicStone(new MagicStoneToTower1())) {
					writeOut("Varazsko hozzaadva");
				} else {
					writeOut("Nem lehet varazskovet elhelyezni");
				}
			}
		}
		if (!hasObstacle) {
			writeOut("Nem lehet varazskovet elhelyezni");
		}
	}

	public static void placeMagicStoneToObstacle() throws IOException {
		if (obstacles.size() < 1) {
			writeOut("Nem lehet varazskovet elhelyezni");
		} else {
			Random rand = new Random();
			if (obstacles.get(rand.nextInt(obstacles.size())).addMagicStone(new MagicStoneToObstacle())) {
				writeOut("Varazsko1 hozzaadva");
			} else {
				writeOut("Nem lehet varazskovet elhelyezni");
			}
		}

	}

	public static void addFogToField(int x, int y, int id, boolean isDisappearAutomatically) throws IOException {
		Fog fog = new Fog(mordor.getField(x, y), fogControlMode.equals("MANUAL"), isDisappearAutomatically);
		if (fogControlMode.equals("AUTO")) {

		} else {

		}
		fogMap.put(id, fog);
		writeOut("kod hozzaadva");
	}

	public static void removeFog(int id) throws IOException {
		Fog fog = fogMap.get(id);
		fog.remove();
		writeOut("kod torolve");
	}

	public static void moveFog(int move) {
		fogMap.get(1).setMove(move);
	}

	public static void simulateWorld(int time) throws IOException {
		for (Integer j = 0; j < (time * 2); j++) {
			long startTime = System.currentTimeMillis();
			mordor.updateWorld();
			if (Player.getIsEndOfWorld()) {
				writeOut("ellenseg beert");
				break;
			}
			long duration = System.currentTimeMillis() - startTime;
			if (duration < 500) {
				try {
					Thread.sleep(500 - duration);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static void print() throws IOException {
		writeOut("{");
		writeOut(Player.toStringStatic());
		writeOut(mordor + "}");

	}

	public static void autoGenerateMap(int x, int y) throws IOException {
		mordor = new Mordor(x, y, 1);
		writeOut("palya letrehozva");
	}

	public static void createMapBegin(int x, int y, BufferedReader br) throws IOException {
		if (mordor == null) {
			String line;
			StringBuilder map = new StringBuilder();
			for (int i = 0; i < x; i++) {
				line = br.readLine();
				if (line == null || line.equals("createMapEnd") || line.length() != (y * 2)) {
					writeOut("Fatal error: Hibas map deklaracio!");
					exit();
				} else {
					map.append(line);
				}
			}
			line = br.readLine();
			if (line != null && line.equals("createMapEnd")) {
				mordor = new Mordor(x, y, map.toString());
				writeOut("palya letrehozva");
			} else {
				writeOut("Fatal error: Hibas map deklaracio!");
				exit();
			}
		} else {
			writeOut("Mar van palya!");
		}
	}

	public static void initPlayer() throws IOException {
		Random rand = new Random();
		initPlayer(rand.nextInt(300));
	}

	public static void initPlayer(int witchcraft) throws IOException {
		Player.setWitchcraft(witchcraft);
		writeOut("player INIT:" + witchcraft);
	}

	public static void loadFromFile(String fileName) throws IOException {
		writeOut(fileName + " betoltve");
		execute(new BufferedReader(new FileReader(fileName)));
	}

	public static void saveToFile(String fileName) throws IOException {
		outputFile = fileName;
		bw.add(new BufferedWriter(new FileWriter(fileName)));
		writeOut(fileName + " elmentve");
	}

	public static void exit() throws IOException {
		for (BufferedWriter bufferedWriter : bw) {
			bufferedWriter.close();
		}
		System.exit(0);
	}

	public static void writeOut(String output) throws IOException {
		for (BufferedWriter bufferedWriter : bw) {
			bufferedWriter.write(output);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
	}

}